package com.ruiysoft.security.tokenGranter;

import com.alibaba.fastjson.JSON;
import com.ruiysoft.security.service.CustomAuthorizationCodeService;
import com.ruiysoft.security.service.RedisClientDetailsService;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.provider.CompositeTokenGranter;
import org.springframework.security.oauth2.provider.OAuth2RequestFactory;
import org.springframework.security.oauth2.provider.TokenGranter;
import org.springframework.security.oauth2.provider.client.ClientCredentialsTokenGranter;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeTokenGranter;
import org.springframework.security.oauth2.provider.implicit.ImplicitTokenGranter;
import org.springframework.security.oauth2.provider.password.ResourceOwnerPasswordTokenGranter;
import org.springframework.security.oauth2.provider.refresh.RefreshTokenGranter;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.StandardStringSerializationStrategy;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by 化增光 on 2018/10/28.
 */
@Component
public class CustomTokenGranter {

//    @Resource
//    RedisUserDetailsService redisUserDetailsService;

    @Resource
    AuthenticationManager authenticationManager;

    @Resource
    RedisClientDetailsService redisClientDetailsService;

    @Resource
    RedisConnectionFactory redisConnectionFactory;

    OAuth2RequestFactory oAuth2RequestFactory;

    @Bean("tokenGranter")
    protected TokenGranter tokenGranter() throws Exception {
        List<TokenGranter> tokenGranters = new ArrayList<>();

        //授权码模式
        tokenGranters.add(new AuthorizationCodeTokenGranter(tokenServices(), authorizationCodeServices(),
                redisClientDetailsService, requestFactory()));

        //刷新token
        tokenGranters
                .add(new RefreshTokenGranter(tokenServices(), redisClientDetailsService, requestFactory()));

        //简化模式
        tokenGranters
                .add(new ImplicitTokenGranter(tokenServices(), redisClientDetailsService, requestFactory()));

        //客户端模式
        tokenGranters.add(
                new ClientCredentialsTokenGranter(tokenServices(), redisClientDetailsService, requestFactory()));

        //密码模式
        tokenGranters.add(new ResourceOwnerPasswordTokenGranter(authenticationManager, tokenServices(),
                redisClientDetailsService, requestFactory()));

        //小程序模式
        tokenGranters.add(new MicroprogramCodeTokenGranter(authenticationManager, tokenServices(),
                redisClientDetailsService, requestFactory()));

        TokenGranter tokenGranter = new CompositeTokenGranter(tokenGranters);
        return tokenGranter;
    }

    @Bean("redisTokenStore")
    public RedisTokenStore redisTokenStore(){
        RedisTokenStore store =new RedisTokenStore(redisConnectionFactory);
        //store.setSerializationStrategy(new FastJsonStoreSerializationStrategy());
        //store.setSerializationStrategy(new JdkSerializationStrategy());
        //store.setSerializationStrategy(new JSONSerializationStrategy());
        //store.setPrefix("O2:");
        return store;
    }

    private AuthorizationServerTokenServices tokenServices() {
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        tokenServices.setTokenStore(redisTokenStore());
        tokenServices.setSupportRefreshToken(true);
        tokenServices.setClientDetailsService(redisClientDetailsService);
        return tokenServices;
    }

    private AuthorizationCodeServices authorizationCodeServices(){
        CustomAuthorizationCodeService customAuthorizationCodeServices = new CustomAuthorizationCodeService(redisConnectionFactory);
        return customAuthorizationCodeServices;
    }

    private OAuth2RequestFactory requestFactory() {
        if (oAuth2RequestFactory != null) {
            return oAuth2RequestFactory;
        }
        oAuth2RequestFactory = new DefaultOAuth2RequestFactory(redisClientDetailsService);
        return oAuth2RequestFactory;
    }




    public static class JSONSerializationStrategy extends StandardStringSerializationStrategy {
        @Override
        protected <T> T deserializeInternal(byte[] bytes, Class<T> clazz) {
            return JSON.parseObject(bytes,clazz);
        }

        @Override
        protected byte[] serializeInternal(Object object) {
            return JSON.toJSONBytes(object);
        }
    }

}
